#ifndef __data_shuttle_base_task_header_file_h__
#define __data_shuttle_base_task_header_file_h__

#include "common.h"
#include "datashuttle.h"

namespace datashuttle
{

const int	TYPE_TASK_NULL		=	0;
const int	TYPE_TASK_DATAIN	=	(1 << 0);
const int	TYPE_TASK_DATAOUT	=	(1 << 1);
const int	TYPE_TASK_ERROR		=	(1 << 2);
const int	TYPE_TASK_TIMER		=	(1 << 3);

/// 通常情况下,IoLoop都只有一个实例，所以不要继承自SharedObject比较好
/// 
class BaseTask;
typedef Pointer<BaseTask> BaseTaskPtr;
class EventTask;
typedef Pointer<EventTask> EventTaskPtr;

class IoLoop
{
public:
	virtual ~IoLoop(){}
	//
	//IoLoop的主要作用和注意事项
	//    1. 提供timer计时功能
	//    2. 提供Io事件通知功能
	//       现在我还不能肯定是否可以使用IoLoop来通知关于文件Io的事件
	//       不过可以肯定的是网络IO事件是可以通过IoLoop来获取到的
	//    3. 注意事项： 由于IoLoop采用了一个浮动窗口来处理timer事件。
	//                  同时，为了效率方面的考虑，如果某一个task的设置
	//                  timer并且在timer过期之前取消掉这个timer的话，在IoLoop实例
	//                  的TimerTable中会留出一个空洞，也就是TimerTable在这个位置
	//                  上的内容是空的。但是IoLoop不会记录这个位置为Free，并且为
	//                  后续的timer设置占用这个空洞。只有当这个空洞所处的位置已经
	//                  被消耗掉以后此位置才会被再次使用。所以任何Task的timer的多
	//                  次设置将会暂用多个TimerTable的位置（不过是new还是update）。
	//                  这个是一个需要注意的地方，频繁多次的设置timer会对系统的性
	//                  能造成影响。请始终遵循一个Task在大部分时间只设置一次Timer.
	//                  除非十分有必要才会去做update(remove&&add).
	
	virtual bool	addFd( EventTaskPtr task ){ return false; }
	virtual void	removeFd( EventTaskPtr task ){}
	virtual bool	addTask( BaseTaskPtr task ){ return false; }
	virtual void	removeTask( BaseTaskPtr task){} 
};


/// Task is a base execution unit in datashuttle, and you MUST only run a task via scheduler,
/// especially if you want to delete a task instance
class BaseTask : public SharedObject
{
public:
	BaseTask( IoLoop& loop);
	virtual ~BaseTask(){}

	/// is current task valid for running
	virtual bool isValid( ) const = 0;
	
	/// task should implement this function to perform action 
	/// and BE NOTICED that DO NOT RUN ANY BLOCKING CALL in this function or else the scheduler will get hung
	virtual void run( int type ) = 0 ; 

	/// if service is going down, routine cancel will be invoked, you can do some resource release action
	/// NOTE: only when service is going down, this routine may be invoked
	virtual void cancel() = 0;

public:

	void setTimer( long long tte );
	void killTimer( );

	/// when should curent task to be run, the return value is a time type presented by milliseconds
	inline long long targetTime() const 
	{
		return mTargetTime;
	}

	inline	long long deltaTime() const
	{
		return mDeltaTime;
	}

	inline void setTimerTablePosition( size_t rowId, size_t colId)
	{
		mTimerRowId = rowId;
		mTimerColId = colId;
	}

	inline size_t timerTableRowId( ) const
	{
		return mTimerRowId;
	}
	inline size_t timerTableColId() const
	{
		return mTimerColId;
	}

	inline void resetTimerTablePosition( )
	{
		mTimerRowId = mTimerColId = (size_t)-1;
	}

	/// how many milliseconds left from now to the expire time, if task expired, 0 is returned
	inline long long timeToExpire() const 
	{
		long long delta = mTargetTime - timenow();
		delta = delta < 0 ? 0 : delta;
		return delta;
   	}

protected:
	IoLoop&		mLoop;

private:

	long long	mTargetTime;//when should this task get running
	long long	mDeltaTime;
	size_t		mTimerRowId;
	size_t		mTimerColId;
};


// TODO: 如果EventTask也使用BaseTask的run函数，那么如何区别
// POLLIN还是POLLOUT的事件到达呢？
class EventTask : public BaseTask
{
public:
	EventTask( IoLoop& loop );
	virtual ~EventTask();

	/// NOTE: please update file descriptor after initialize the EventTask successfully
	inline void		updateFd( int fd ) { mFd = fd; }
	inline int		getFd( ) const { return mFd ;}

	bool	addToIoLoop();

	void	removeFromIoLoop();

private:
	int			mFd;
	//  由于我们自己采用了智能指针的方式来管理instance的生命周期,
	//  但是epoll拥有的是task的原始指针而不是智能指针，也就是说如果
	//  应用程序已经不用有任何的instance的引用的时候epoll可能还有一
	//  份原始指针的引用，那么这个将会导致程序crash。
	//  为了避免这种情况的发生，这里用一个mSelf智能指针增加对instance的引用。
	//  因为增加了这个引用，EventTask必须显示的close，才能正确的释放instance资源
	BaseTaskPtr	mSelf;
};

enum COMM_ERROR
{
	COMM_ERROR_OK			= 0,			// operation successfully
	COMM_ERROR_AGAIN		= -1,		// operation can't be performed immediately, please wait for another chance
	COMM_ERROR_ERROR		= -2,		// operation failed
	COMM_ERROR_NOTSOCK		= -3,	// socket handle is not valid, you should call create 
};

//实质上Communicator是一个socket的封装
class Communicator: public noncopyable
{
public:
	Communicator( );
	Communicator( int sock );
	virtual ~Communicator();

public:

	bool	create( int family );//create a socket instance via PF_INET or PF_INET6

	bool	bind( const std::string& address, const std::string& port );
	bool	bind( const struct addrinfo* info);

	bool	listen( int backlog = 5 );

	Communicator* accept();

	bool	connect( const std::string& address, const std::string& port );
	bool	connect( const addrinfo* info);

	void	shutdown();


	//read date from the communicator
	//@param buf, the buffer to hold the data
	//@size, size in byte of the buffer area
	//@return the actual read size in bytes, <0 if error.
	//  may return COMM_STATUS_AGAIN which means current action is not performed successfully and you should run it in another time
	int		read( char* buf, size_t size);

	//write data to the communicator
	//@param buf, the buffer area contain the data to be written
	//@param size, size in byte of the buffer area
	//  may return COMM_STATUS_AGAIN which means current action is not performed successfully and you should run it in another time
	int		write( const char* buf, size_t size);

	bool	setNonBlock();
	bool	setBlock();
	bool	setWriteBuf( size_t bufSize );
	bool	setReadBuf( size_t bufSize);
	bool	setWriteTimeo( size_t toms);
	bool	setReadTimeo(size_t toms);

	int		getSock(){ return mSock;}

	bool	getLocalInfo( std::string& ip, std::string& port ) const;
	bool	getPeerInfo( std::string& ip, std::string& port ) const;

	COMM_ERROR errcode2status( int err );
	
	COMM_ERROR lastError() const;

private:
	int		mSock;
};

class CommunicationTask : public EventTask, public noncopyable
{
public:

	CommunicationTask( IoLoop& loop );
	virtual ~CommunicationTask();

	///act like a server, listen at a specified address/port, accept new communicator
	bool	listenAt( const std::string& address, const std::string& port , int backlog = 1000 );

	///act like a client, bind local address/port, connect to server according to peer address/port
	bool	connectTo( const std::string& peerAddress, const std::string& peerPort, const std::string& localAddress="", const std::string& localPort="");

	///注意： 使用createFrom以后Communicator的生命周期会由CommunicationTask来管理
	bool	createFrom( Communicator* comm );

	void	close();	

	inline 	Communicator*	getComm(){ return mComm; }

	bool	isCommValid( ) const;

	bool	getLocalInfo( std::string& ip, std::string& port ) const
	{
		if(!mComm) return false;
		return mComm->getLocalInfo(ip,port);
	}

	bool	getPeerInfo( std::string& ip, std::string& port ) const
	{
		if(!mComm) return false;
		return mComm->getPeerInfo(ip,port);
	}

	COMM_ERROR lastError() const

protected:
	
	virtual bool isValid( ) const;

	virtual void run( int type );
	
	virtual void cancel();

	void	clearResource();

protected:

	///implement canRead if you care about the incoming data on the communicator
	///This method notify that there is some data can be read from the communicator
	virtual void canRead(){}

	///This method notify that there is room for curernt communicator to be written
	virtual void canWrite(){}
	
	/// communicator is created and connected to/from peer
	virtual void onCreated(){}

	///comunicator is closed, communicator is not valid at this stage
	virtual void onClosed(){}

	/// some thing happened
	virtual void onError(){}

	///timer expired
	virtual void onTimer(){}

	///service is going down
	virtual void onCancel(){}

	enum COMM_STATE
	{
		COMM_STATE_INIT,			// COMM instance被建立起来，此时还没有任何的
		COMM_STATE_CREATED,			// COMM已经链接成功
		COMM_STATE_REQ_CREATED,
		COMM_STATE_PENDING,
		COMM_STATE_CLOSED
	};

	void updateState( COMM_STATE state )
	{
		mState = state;
	}
private:
	Communicator*	mComm;
	COMM_STATE		mState;
};

typedef Pointer<CommunicationTask> CommunicationTaskPtr;

class CommunicationServer: public CommunicationTask
{
public:
	CommunicationServer( IoLoop& loop);
	virtual ~CommunicationServer();

protected:
	virtual void canRead();
	virtual void onError();
	virtual void onCancel();
};


class TaskFactory : public SharedObject
{
public:
	TaskFactory( IoLoop& loop );
	virtual ~TaskFactory();

	virtual BaseTaskPtr createTask(IoLoop& loop );

	virtual void		releaseTask( BaseTaskPtr task );

protected:
	IoLoop&		mLoop;
};

class EventTaskFactory: public TaskFactory
{
public:
	EventTaskFactory( IoLoop& loop );
	virtual ~EventTaskFactory();

	virtual BaseTaskPtr createTask(IoLoop& loop );

	virtual void		releaseTask( BaseTaskPtr task );
};


}//namespace datashuttle
#endif// __data_shuttle_base_task_header_file_h__

